/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds.object;

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import net.worlds.AssetLoader;
import net.worlds.AssetManager;
import net.worlds.WorldsException;
import net.worlds.Main;
import net.worlds.PropChangeHandler;
import net.worlds.Util;
import net.worlds.lua.Event;
import org.jbox2d.collision.shapes.PolygonDef;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2D;
import se.krka.kahlua.vm.JavaFunction;
import se.krka.kahlua.vm.LuaCallFrame;


public class Tool extends Part {
    private BufferedImage image = null;
    private final int[] xVerts = new int[4];
    private final int[] yVerts = new int[4];
    private long dropTime;
    public Tool() throws WorldsException
    {
        super("Tool");
        constructor();
    }
    private void disableTool() throws WorldsException
    {
        disable();
    }
    private void enableTool() throws WorldsException
    {
        enable();
        setProp("Velocity", Vec2D.ORIGIN, true);
    }
    public Tool(String t) throws WorldsException
    {
        super(t);
        constructor();
    }
    public void draw(Graphics g) throws WorldsException
    {
        PolygonShape poly = (PolygonShape) shape;
        if(body == null || shape == null)
            return;
        if(disabled || getParent() instanceof Inventory)
            return;
        Vec2D[] vertices = poly.getVertices();
        for(int v=0; v < poly.m_vertexCount; ++v)
        {
            if(vertices[v] != null)
            {
                Vec2D v2 = body.getWorldPoint(vertices[v]);
                Vec2D screenVec = new Vec2D(v2.x, v2.y).worldToScreen(Main.getView());
                xVerts[v] = (int) screenVec.x;
                yVerts[v] = (int) screenVec.y;
            }
        }
        if(texture != null)
        {
            Vec2D screenSize = getVec2DProp("Size").toScreenUnits();
            int screenWidth = (int) screenSize.x;
            int screenHeight = (int) screenSize.y;
            Graphics2D g2 = (Graphics2D) g;
            Vec2D worldPos = new Vec2D(body.getPosition());
            Vec2D imgPos = worldPos.add(new Vec2D(-getVec2DProp("Size").x, getVec2DProp("Size").y).mul(0.5f)).worldToScreen(Main.getView());
            Vec2D rotateCenter = worldPos.worldToScreen(Main.getView());
            AffineTransform original = g2.getTransform();
            AffineTransform scale = AffineTransform.getScaleInstance(scaleDimensionForScreen(texture.getWidth(), getVec2DProp("Size").x), scaleDimensionForScreen(texture.getHeight(), getVec2DProp("Size").y));
            AffineTransform rotate = AffineTransform.getRotateInstance(-body.getAngle(), rotateCenter.x, rotateCenter.y);
            g2.transform(rotate);
            g2.transform(scale);
            g2.drawImage(texture, (int) (imgPos.x / ((Main.getView().scaleFactor * getVec2DProp("Size").x)/texture.getWidth())), (int) (imgPos.y / ((Main.getView().scaleFactor * getVec2DProp("Size").y)/texture.getHeight())), null);
            g2.setTransform(original);
        }
        if(selected)
        {
            g.setColor(Color.white);
            g.drawPolygon(xVerts, yVerts, xVerts.length);
        }
        if(label != null)
        {
            Vec2D center = getPosition().worldToScreen(Main.getView());
            FontMetrics fm = g.getFontMetrics();
            Rectangle2D r = fm.getStringBounds(label, g);
            int textX = (int) (center.x - r.getWidth()/2);
            int textY = (int) (center.y - getVec2DProp("Size").toScreenUnits().y/2 - 10);
            g.setColor(Color.black);
            g.drawString(label, textX + 1, textY + 1);
            g.setColor(Color.white);
            g.drawString(label, textX, textY);
        }
    }
    private void constructor() throws WorldsException
    {
        /*addPropChangeHandler("Parent", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws BuildismException {
                onParentChanged((GameObject) oldValue, (GameObject) value);
                if(value instanceof Inventory && isInWorld)
                    disable();
                else if(!(value instanceof Inventory) && !isInWorld)
                    enableTool();
                if(oldValue != null && oldValue instanceof Inventory && ((GameObject) oldValue).getParent() == Main.getPlayer())
                    Main.getLocalPlayer().removeTool((Tool) instance);
                else if(value != null && value instanceof Inventory && ((GameObject) value).getParent() == Main.getPlayer())
                    Main.getLocalPlayer().addTool((Tool) instance);
            }

        });*/
        addPropChangeHandler("Size", new PropChangeHandler()
        {

            @Override
            public void handle(final Object oldValue, final Object value) throws WorldsException {

                try {
                    Vec2D vec = (Vec2D) value;
                    ((PolygonDef) sd).setAsBox((float) vec.x / 2, (float) vec.y / 2);
                    if(inWorld)
                    {
                        rebuildShape();
                        setProp("Texture", getProp("Texture"), true);
                    }
                } catch (WorldsException ex) {
                    Main.error(ex);
                }
            }

        });
        addPropChangeHandler("Holdable", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                boolean v = (Boolean) value;
                if(!v)
                {
                    disableTool();
                }
                else
                {
                    enableTool();
                    setProp("Velocity", new Vec2D(0, 5), true);
                }
            }

        });
        addPropChangeHandler("Texture", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                final String path = value.toString();
                if(!Main.noView)
                {
                    Runnable r = new Runnable()
                    {

                        public void run() {
                            try
                            {
                                setTexture(AssetManager.tileTexture(AssetManager.loadImage(path, path), (int) (getVec2DProp("Size").x * Main.getView().scaleFactor), (int) (getVec2DProp("Size").y * Main.getView().scaleFactor), false, false, false, false));
                            } catch (Exception ex) {
                                System.err.println("Invalid texture URL");
                            }
                        }
                    };
                    AssetLoader.getInstance().addItem(r);
                }
            }
        });
        sd = new PolygonDef();
        ((PolygonDef)sd).setAsBox(2.5f, 2.5f);
        sd.restitution = 0.4f;
        sd.density = 1;
        sd.friction = 0.8f;
        bd.position = new Vec2D(0, 0);

        //x_;
        try {
            image = AssetManager.loadImage("resource://objects/Tool.png", "resource://objects/Tool.png");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        addPropChangeHandler("Parent", new PropChangeHandler() {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                onParentChanged((GameObject) oldValue, (GameObject) value);
                if(value != null && value instanceof Inventory && ((((GameObject) value).getParent() == Main.getPlayer() && Main.getPlayer() != null) || Main.isServer()))
                {
                    if(value != oldValue && Main.getLocalPlayer() != null)
                        Main.getLocalPlayer().addTool((Tool) instance);
                    synchronized(children)
                    {
                        for(GameObject s : children)
                        {
                            if(s instanceof Script && s.getBooleanProp("Enabled"))
                            {
                                ((Script)s).run();
                            }
                        }
                    }
                    disableTool();
                }
                else if(Main.getPlayer() != null && oldValue != null && !(value instanceof StarterInventory))
                {
                    if(((GameObject) oldValue).getParent() == Main.getPlayer() && oldValue instanceof Inventory)
                        Main.getLocalPlayer().removeTool((Tool) instance);
                    enableTool();
                }
                else if(value instanceof Inventory && Main.isServer())
                    disableTool();
                else if(value instanceof StarterInventory)
                    disableTool();
            }
        });
        addPropChangeHandler("Image", new PropChangeHandler() {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                final String path = value.toString();
                AssetLoader.getInstance().addItem(new Runnable()
                {
                    public void run() {
                    try
                    {
                        image = AssetManager.loadImage(path, path);
                    } catch (IOException ex) {
                        throw new RuntimeException("Invalid texture URL");
                    }
                    }
                });
            }
        });
        addFunction("getAngle", new JavaFunction()
        {
            public int call(LuaCallFrame callFrame, int nArguments) {
                if(Main.getLocalPlayer() != null && Main.getLocalPlayer().getCharacter() != null)
                    callFrame.push(-Math.toDegrees(Main.getLocalPlayer().getCharacter().mouseAngle));
                else
                    callFrame.push(0);
                return 1;
            }
        });
        addFunction("getPosition", new JavaFunction()
        {
            public int call(LuaCallFrame callFrame, int nArguments) {
                double tx = 0;
                double ty = 0;
                if(nArguments == 3 && Util.isDouble(callFrame.get(1).toString()) && Util.isDouble(callFrame.get(2).toString()))
                {
                    tx = (Double) callFrame.get(1);
                    ty = (Double) callFrame.get(2);
                }
                if(Main.getLocalPlayer() != null && Main.getLocalPlayer().getCharacter() != null)
                {
                    try {
                        Vec2D vec = new Vec2D(-Main.getLocalPlayer().getCharacter().mouseAngle).mul(getVec2DProp("Size").x);
                        callFrame.push(vec.add(Main.getLocalPlayer().getTorso().getPosition().add(new Vec2D(0, 1.5f))));
                        return 1;
                    } catch (WorldsException ex) {
                        throw new RuntimeException(ex);
                    }
                }
                else
                {
                    callFrame.pushNil();
                    return 1;
                }
            }
        });
        addEvent("Selected", new Event(), "none");
        addEvent("Deselected", new Event(), "none");
        addEvent("MouseDown", new Event(), "b (integer), position (Vec2D)");
        addEvent("MouseDragged", new Event(), "b (integer), position (Vec2D)");
        addEvent("MouseUp", new Event(), "b (integer), position (Vec2D)");
        addEvent("KeyDown", new Event(), "keyCharacter (string)");
        addEvent("KeyUp", new Event(), "keyCharacter (string)");
    }
    public BufferedImage getImage()
    {
        return image;
    }
    public BufferedImage getTexture()
    {
        return texture;
    }
    @Override
    public void onCollided(final Part other, final Vec2D vel)
    {
        super.onCollided(other, vel);
        if(Main.isClient())
            return;
        if(System.currentTimeMillis() - dropTime < 1000)
            return;
        try {
            if (other.getParent() instanceof Character && !disabled)
            {
                //Player p = (Player) Main.getActiveWorld().getService("Players").getChild(other.toString());
                disableTool();
                Main.runInMainThread(new Runnable()
                {
                    public void run() {
                        try {
                            setProp("Parent", world.getService("Players").getChild(other.getParent().getStringProp("Name")).getChild("Inventory"), true);
                        } catch (WorldsException ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                });
            }
        } catch (WorldsException ex) {
            throw new RuntimeException(ex);
        }
    }
    public void drop() throws WorldsException
    {
        setProp("Parent", world.getService("World"), true);
        dropTime = System.currentTimeMillis();
    }
    public void selected()
    {
        getEvent("Selected").fire(Event.NULL);
        if(Main.isClient())
        {
            Main.getClient().sendToolActive(this, true);
        }
    }
    public void deselected()
    {
        getEvent("Deselected").fire(Event.NULL);
        if(Main.isClient())
        {
            Main.getClient().sendToolActive(this, false);
        }
    }
    public void mouseDown(int b, Vec2D worldPoint)
    {
        getEvent("MouseDown").fire(new Object[]{b, worldPoint});
        if(Main.isClient())
        {
            Main.getClient().sendToolMouse(this, 0, b, worldPoint);
        }
    }
    public void mouseDragged(int b, Vec2D worldPoint)
    {
        getEvent("MouseDragged").fire(new Object[]{b, worldPoint});
        if(Main.isClient())
        {
            Main.getClient().sendToolMouse(this, 1, b, worldPoint);
        }
    }
    public void mouseUp(int b, Vec2D worldPoint)
    {
        getEvent("MouseUp").fire(new Object[]{b, worldPoint});
        if(Main.isClient())
        {
            Main.getClient().sendToolMouse(this, 2, b, worldPoint);
        }
    }
    public void keyDown(String k)
    {
        getEvent("KeyDown").fire(new Object[]{k});
        if(Main.isClient())
        {
            Main.getClient().sendToolKey(this, 0, k);
        }
    }
    public void keyUp(String k)
    {
        getEvent("KeyUp").fire(new Object[]{k});
        if(Main.isClient())
        {
            Main.getClient().sendToolKey(this, 1, k);
        }
    }
}
